package cn.dansj.common.request.annotation.encrypt;

import cn.dansj.common.processor.TargetType;
import cn.dansj.common.processor.meta.WriteToResource;
import cn.dansj.common.request.advisor.AbstractAnnotationPointerAdvisor;
import cn.dansj.common.utils.crypt.AesUtils;
import cn.dansj.common.utils.json.JSONUtils;
import cn.dansj.common.utils.transfer.RandomUtils;
import cn.dansj.common.utils.transfer.Verification;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.Field;

@WriteToResource(type = TargetType.Imports, keyProperty = "org.springframework.boot.autoconfigure.AutoConfiguration")
public class EncryptResponseDataAspect extends AbstractAnnotationPointerAdvisor<EncryptResponseData> {
    @Override
    public Object execute(MethodInvocation invocation) throws Throwable {
        return transferData(invocation.proceed(), getGenericAnnotation(invocation.getMethod()).filed(), invocation.getMethod().getReturnType());
    }

    @Override
    public int getOrder() {
        return 20;
    }

    public static Object transferData(Object obj, String encryptColumn, Class<?> returnType) {
        if (Verification.checkNotNull(obj) && Verification.checkNotNull(encryptColumn) && hasAttribute(obj, encryptColumn)) {
            setEncryptData(obj, encryptColumn);
        } else if (returnType.equals(Object.class) || returnType.equals(String.class)) {
            obj = encryptData(obj);
        }
        return obj;
    }

    public static boolean hasAttribute(Object object, String attribute) {
        for (Field field : object.getClass().getDeclaredFields()) {
            if (field.getName().equals(attribute)) {
                return true;
            }
        }
        return false;
    }

    public static void setEncryptData(Object obj, String field) {
        try {
            final Class<?> objClass = obj.getClass();
            final Field declaredField = objClass.getDeclaredField(field);
            declaredField.setAccessible(true);
            declaredField.set(obj, encryptData(getData(obj, field)));
        } catch (Exception exception) {
            throw new IllegalArgumentException("设置加密数据失败");
        }
    }

    public static Object getData(Object obj, String field) {
        try {
            final Field[] declaredFields = obj.getClass().getDeclaredFields();
            for (Field field1 : declaredFields) {
                if (field1.getName().equals(field)) {
                    field1.setAccessible(true);
                    return field1.get(obj);
                }
            }
            return null;
        } catch (Exception exception) {
            return null;
        }
    }

    public static Object encryptData(Object obj) {
        if (obj == null) {
            return null;
        }
        try {
            final String randomPrefix = RandomUtils.generate(RandomUtils.randomInt(5, 15), false) + RandomUtils.randomCharacter("/+");
            final String secretKey = RandomUtils.generate(32);
            final String encrypt = AesUtils.encrypt(JSONUtils.toJSON(obj), secretKey);
            return "$$" + randomPrefix + secretKey + encrypt;
        } catch (Exception exception) {
            throw new IllegalArgumentException("数据加密失败");
        }
    }
}